home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-03  |  7.5 KB  |  369 lines

  1. #include "sysincludes.h"
  2. #include "msdos.h"
  3. #include "stream.h"
  4. #include "mtools.h"
  5. #include "fsP.h"
  6. #include "file.h"
  7. #include "htable.h"
  8.  
  9. typedef struct File_t {
  10.     Class_t *Class;
  11.     int refs;
  12.     struct Fs_t *Fs;    /* Filesystem that this fat file belongs to */
  13.     Stream_t *Buffer;
  14.  
  15.     int (*map)(struct File_t *this, int where, int *len, int mode);
  16.     unsigned long FileSize;
  17.  
  18.     /* Absolute position of first cluster of file */
  19.     unsigned short FirstAbsCluNr;
  20.  
  21.     /* Absolute position of previous cluster */
  22.     unsigned short PreviousAbsCluNr;
  23.  
  24.     /* Relative position of previous cluster */
  25.     unsigned short PreviousRelCluNr;
  26.     struct directory dir;
  27. } File_t;
  28.  
  29. static int normal_map(File_t *This, int where, int *len, int mode)
  30. {
  31.     int offset;
  32.     int NrClu; /* number of clusters to read */
  33.     unsigned short RelCluNr;
  34.     unsigned short CurCluNr;
  35.     unsigned short NewCluNr;
  36.     unsigned short AbsCluNr;
  37.     int clus_size;
  38.     Fs_t *Fs = This->Fs;
  39.  
  40.     clus_size = Fs->cluster_size * Fs->sector_size;
  41.     offset = where % clus_size;
  42.  
  43.     if (mode == MT_READ)
  44.         maximize(len, This->FileSize - where);
  45.     if (*len <= 0 ){
  46.         *len = 0;
  47.         return 0;
  48.     }
  49.  
  50.     if (This->FirstAbsCluNr < 2){
  51.         if( mode == MT_READ || *len == 0){
  52.             *len = 0;
  53.             return 0;
  54.         }
  55.         NewCluNr = get_next_free_cluster(This->Fs, 1);
  56.         if (NewCluNr == 1 ){
  57.             errno = ENOSPC;
  58.             return -2;
  59.         }
  60.         This->FirstAbsCluNr = NewCluNr;
  61.         Fs->fat_encode(This->Fs, NewCluNr, Fs->end_fat);
  62.     }
  63.  
  64.     RelCluNr = where / clus_size;
  65.     
  66.     if (RelCluNr >= This->PreviousRelCluNr){
  67.         CurCluNr = This->PreviousRelCluNr;
  68.         AbsCluNr = This->PreviousAbsCluNr;
  69.     } else {
  70.         CurCluNr = 0;
  71.         AbsCluNr = This->FirstAbsCluNr;
  72.     }
  73.  
  74.  
  75.     NrClu = (offset + *len - 1) / clus_size;
  76.     while (CurCluNr <= RelCluNr + NrClu){
  77.         if (CurCluNr == RelCluNr){
  78.             /* we have reached the beginning of our zone. Save
  79.              * coordinates */
  80.             This->PreviousRelCluNr = RelCluNr;
  81.             This->PreviousAbsCluNr = AbsCluNr;
  82.         }
  83.         NewCluNr = Fs->fat_decode(This->Fs, AbsCluNr);
  84.         if (NewCluNr == 1 ){
  85.             fprintf(stderr,"Fat problem while decoding %d\n", 
  86.                 AbsCluNr);
  87.             cleanup_and_exit(1);
  88.         }
  89.         if(CurCluNr == RelCluNr + NrClu)            
  90.             break;
  91.         if (NewCluNr == Fs->end_fat && mode == MT_WRITE){
  92.             /* if at end, and writing, extend it */
  93.             NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr);
  94.             if (NewCluNr == 1 ){ /* no more space */
  95.                 errno = ENOSPC;
  96.                 return -2;
  97.             }
  98.             Fs->fat_encode(This->Fs, AbsCluNr, NewCluNr);
  99.             Fs->fat_encode(This->Fs, NewCluNr, Fs->end_fat);
  100.         }
  101.  
  102.         if (CurCluNr < RelCluNr && NewCluNr == Fs->end_fat){
  103.             *len = 0;
  104.             return 0;
  105.         }
  106.  
  107.         if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
  108.             break;
  109.         CurCluNr++;
  110.         AbsCluNr = NewCluNr;
  111.     }
  112.  
  113.     maximize(len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
  114.  
  115.     return ((This->PreviousAbsCluNr - 2) * Fs->cluster_size +
  116.         Fs->dir_start + Fs->dir_len) *
  117.             Fs->sector_size + offset;
  118. }
  119.  
  120.  
  121. static int root_map(File_t *This, int where, int *len, int mode)
  122. {
  123.     Fs_t *Fs = This->Fs;
  124.  
  125.     maximize(len, Fs->dir_len * Fs->sector_size - where);
  126.     if(*len < 0 ){
  127.         *len = 0;
  128.         errno = ENOSPC;
  129.         return -2;
  130.     }
  131.     return Fs->dir_start * Fs->sector_size + where;
  132. }
  133.     
  134.  
  135. static int read_file(Stream_t *Stream, char *buf, int where, int len)
  136. {
  137.     DeclareThis(File_t);
  138.     int pos;
  139.  
  140.     Stream_t *Disk = This->Fs->Next;
  141.     
  142.     pos = This->map(This, where, &len, MT_READ);
  143.     if(pos < 0)
  144.         return pos;
  145.     return READS(Disk, buf, pos, len);
  146. }
  147.  
  148. static int write_file(Stream_t *Stream, char *buf, int where, int len)
  149. {
  150.     DeclareThis(File_t);
  151.     int pos;
  152.     int ret;
  153.     Stream_t *Disk = This->Fs->Next;
  154.  
  155.     pos = This->map(This, where, &len, MT_WRITE);
  156.     if( pos < 0)
  157.         return pos;
  158.     ret = WRITES(Disk, buf, pos, len);
  159.     if ( ret > 0 && where + ret > This->FileSize )
  160.         This->FileSize = where + ret;
  161.     return ret;
  162. }
  163.  
  164.  
  165. /*
  166.  * Convert an MSDOS time & date stamp to the Unix time() format
  167.  */
  168.  
  169. static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  170. static inline long conv_stamp(struct directory *dir)
  171. {
  172.     struct tm *tmbuf;
  173.     long tzone, dst;
  174.     long accum;
  175.  
  176.     accum = DOS_YEAR(dir) - 1970; /* years past */
  177.  
  178.     /* days passed */
  179.     accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir);
  180.  
  181.     /* leap years */
  182.     accum += (DOS_YEAR(dir) - 1972) / 4L;
  183.  
  184.     /* back off 1 day if before 29 Feb */
  185.     if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3)
  186.             accum--;
  187.     accum = accum * 24L + DOS_HOUR(dir); /* hours passed */
  188.     accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */
  189.     accum = accum * 60L + DOS_SEC(dir); /* seconds passed */
  190.  
  191.     /* correct for Time Zone */
  192. #ifdef HAVE_GETTIMEOFDAY
  193.     {
  194.         struct timeval tv;
  195.         struct timezone tz;
  196.         
  197.         gettimeofday(&tv, &tz);
  198.         tzone = tz.tz_minuteswest * 60L;
  199.     }
  200. #else
  201. #ifdef HAVE_TZSET
  202.     {
  203.         extern long timezone;
  204.         tzset();
  205.         tzone = timezone;
  206.     }
  207. #else
  208.     tzone = 0;
  209. #endif /* HAVE_TZSET */
  210. #endif /* HAVE_GETTIMEOFDAY */
  211.     
  212.     accum += tzone;
  213.  
  214.     /* correct for Daylight Saving Time */
  215.     tmbuf = localtime(&accum);
  216.     dst = (tmbuf->tm_isdst) ? (-60L * -60L) : 0L;
  217.     accum += dst;
  218.     
  219.     return accum;
  220. }
  221.  
  222.  
  223. static int get_file_data(Stream_t *Stream, long *date, unsigned long *size,
  224.              int *type, int *address)
  225. {
  226.     DeclareThis(File_t);
  227.  
  228.     if(date)
  229.         *date = conv_stamp(& This->dir);
  230.     if(size)
  231.         *size = This->FileSize;
  232.     if(type)
  233.         *type = This->dir.attr & 0x10;
  234.     if(address)
  235.         *address = This->FirstAbsCluNr;
  236.     return 0;
  237. }
  238.  
  239. T_HashTable *filehash;
  240.  
  241. static int free_file(Stream_t *Stream)
  242. {
  243.     return hash_remove(filehash, (void *) Stream, 0);
  244. }
  245.  
  246. static Class_t FileClass = { 
  247.     read_file, 
  248.     write_file, 
  249.     0, /* flush */
  250.     free_file, /* free */
  251.     0, /* get_geom */
  252.     get_file_data 
  253. };
  254.  
  255.  
  256. static unsigned int func1(void *Stream)
  257. {
  258.     DeclareThis(File_t);
  259.  
  260.     return This->FirstAbsCluNr ^ (int) This->Fs;
  261. }
  262.  
  263. static unsigned int func2(void *Stream)
  264. {
  265.     DeclareThis(File_t);
  266.  
  267.     return This->FirstAbsCluNr;
  268. }
  269.  
  270. static int comp(void *Stream, void *Stream2)
  271. {
  272.     DeclareThis(File_t);
  273.     File_t *This2 = (File_t *) Stream2;
  274.  
  275.     return This->Fs != This2->Fs ||
  276.         This->FirstAbsCluNr != This2->FirstAbsCluNr;
  277. }
  278.  
  279. static void init_hash(void)
  280. {
  281.     static int is_initialised=0;
  282.     
  283.     if(!is_initialised){
  284.         make_ht(func1, func2, comp, 20, &filehash);
  285.         is_initialised = 1;
  286.     }
  287. }
  288.  
  289.  
  290. Stream_t *open_root(Stream_t *Fs)
  291. {
  292.     File_t *File;
  293.     File_t Pattern;
  294.  
  295.     init_hash();
  296.     Pattern.Fs = (Fs_t *) Fs;
  297.     Pattern.FirstAbsCluNr = 0;
  298.     if(!hash_lookup(filehash, (T_HashTableEl) &Pattern, 
  299.             (T_HashTableEl **)&File, 0)){
  300.         File->refs++;
  301.         Fs->refs--;
  302.         return (Stream_t *) File;
  303.     }
  304.  
  305.     File = New(File_t);
  306.     File->Fs = (Fs_t *) Fs;
  307.     if (!File)
  308.         return NULL;
  309.     
  310.     File->FileSize = -1;
  311.     File->Class = &FileClass;
  312.     File->map = root_map;
  313.     File->refs = 1;
  314.     File->Buffer = 0;
  315.     hash_add(filehash, (void *) File);
  316.     return (Stream_t *) File;
  317. }
  318.  
  319. Stream_t *open_file(Stream_t *Fs, struct directory *dir)
  320. {
  321.     File_t *File;
  322.     File_t Pattern;
  323.     int first;
  324.     unsigned long size;
  325.  
  326.     first = START(dir);
  327.  
  328.     if(!first && (dir->attr & 0x10))
  329.         return open_root(Fs);
  330.     
  331.     if (dir->attr & 0x10 )
  332.         size = (1UL << 31) - 1;
  333.     else 
  334.         size = FILE_SIZE(dir);
  335.  
  336.  
  337.     init_hash();
  338.     if(first >= 2){
  339.         /* if we have a zero-addressed file here, it is certainly
  340.          * _not_ the root directory, but rather a newly created
  341.          * file */
  342.         Pattern.Fs = (Fs_t *) Fs;
  343.         Pattern.FirstAbsCluNr = first;
  344.         if(!hash_lookup(filehash, (T_HashTableEl) &Pattern, 
  345.                 (T_HashTableEl **)&File, 0)){
  346.             File->refs++;
  347.             Fs->refs--;
  348.             return (Stream_t *) File;
  349.         }
  350.     }
  351.  
  352.     File = New(File_t);
  353.     if (!File)
  354.         return NULL;
  355.     
  356.     /* memorize dir for date and attrib */
  357.     File->dir = *dir;
  358.     File->Class = &FileClass;
  359.     File->Fs = (Fs_t *) Fs;
  360.     File->map = normal_map;
  361.     File->FirstAbsCluNr = first;
  362.     File->PreviousRelCluNr = 0xffff;
  363.     File->FileSize = size;
  364.     File->refs = 1;
  365.     File->Buffer = 0;
  366.     hash_add(filehash, (void *) File);
  367.     return (Stream_t *) File;
  368. }
  369.